package com.applet.filter;

import com.applet.properties.JwtProperties;
import com.applet.result.Result;
import com.applet.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.entity.ContentType;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 全局过滤器  GlobalFilter                             过滤器 或 拦截器，抛出异常无法被全局异常捕获
 * 全局过滤器  "/*" 表示拦截所有请求
 * 需要在启动类上添加 @ServletComponentScan
 */
@Slf4j
@WebFilter(filterName = "GlobalFilter", urlPatterns = "/*")
public class GlobalFilter extends OncePerRequestFilter {


    // springmvc路径匹配器
    private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    //需要方形的路径 需要放行的资源路径  Swagger的、登录接口、登出接口等
    String[] urls = {"/swagger-ui.html", "/webjars/**", "/swagger-resources", "/swagger-resources/**", "/v2/**", "/csrf",
                     "/user/user/login", "/user/user/logout", "/user/shop/status"};


    //注入token工具实体bean
    @Resource
    private JwtProperties jwtProperties;


    //过滤器拦截方法
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        //System.out.println(jwtProperties);


        // 1.向下转型
        //HttpServletRequest request = (HttpServletRequest) servletRequest;
        //HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setContentType(ContentType.APPLICATION_JSON.toString());

        // 2.获取当前请求路径
        String requestURI = request.getRequestURI();
        log.info("GlobalFilter - 当前请求路径:", requestURI);

        // 3.检验当前请求路径是否是需放行的
        Boolean flag = checkUrl(urls, requestURI);

        // 4.判断结果
        if(flag){
            log.info("GlobalFilter - 当前请求路径: {} 需放行", requestURI);
            filterChain.doFilter(request, response);
            log.info("GlobalFilter - 放行后......");
            // 结束方法，不执行下面代码
            return;
        }

        // 5.不是放行路径，需要校验token
        // 获取token
        String jwtToken = request.getHeader(jwtProperties.getUserTokenName());

        // 6.判断token是否为空
        if( !StringUtils.hasLength(jwtToken) ){  //token为空
            log.info("过滤器-当前资源路径: {} 需要检验，但token为空，请先登录", requestURI);
            // 封装token为空错误信息 并 写回
            Result<Object> error = Result.error("过滤器-token为空，请先登录");
            response.getWriter().println(error);
            // 结束方法，不执行下面代码
            return;
        }

        // 7.token不为空，去掉 “Bearer ”
        String token = jwtToken.replace("Bearer ", "");

        // 8.解析token
        try {
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
        } catch (Exception e) {
            log.info(requestURI + " -- 过滤器，token令牌解析异常 ");
            //封装token解析异常信息 并 写回
            Result<Object> error = Result.error("过滤器-token解析异常，请重新登录页");
            response.getWriter().println(error);
            //结束方法 下面代码不再执行
            return;
        }

        // 9.已登录，放行
        log.info("GlobalFilter - " + requestURI + " - 令牌合法，放行");
        filterChain.doFilter(request, response);
        log.info("GlobalFilter - " + requestURI + " - 放行后......");

    }

    //校验当前路径是都需要放行
    private Boolean checkUrl(String[] urls, String requestURI) {
        for (String url : urls) {
            boolean flag = PATH_MATCHER.match(url, requestURI);
            if(flag){
                return true;
            }
        }
        return false;
    }
}
